import { findDOM, compareTwoVdom } from "./react-dom";

export let updateQueue = {
  isBatchingUpdate: false, //更新队列中是否要执行批量更新
  updaters: new Set(), //updater实例的集合
  batchUpdate() {
    for (let updater of updateQueue.updaters) {
      updater.updateComponent();
    }
    updateQueue.isBatchingUpdate = false;
    updateQueue.updaters.clear();
  },
};

function shouldUpdate(classInstance, nextProps, nextState) {
  let willUpdate = true;
  if (
    classInstance.shouldComponentUpdate &&
    !classInstance.shouldComponentUpdate(nextProps, nextState)
  ) {
    willUpdate = false;
  }
  if (willUpdate && classInstance.componentWillUpdate) {
    classInstance.componentWillUpdate();
  }
  //不管更不更新都需要把最新的状态赋值
  classInstance.state = nextState;
  if (nextProps) classInstance.props = nextProps;
  if (willUpdate) {
    classInstance.forceUpdate();
  }
}

class Updater {
  constructor(classInstance) {
    //类实例
    this.classInstance = classInstance;
    //等待更新状态
    this.pendingStates = [];
    //callback回掉函数
    this.callbacks = [];
  }

  addState(partialState, callback) {
    this.pendingStates.push(partialState);
    if (typeof callback === "function") {
      this.callbacks.push(callback);
    }
    //触发更新
    this.emitUpdate();
  }

  emitUpdate(nextProps) {
    this.nextProps = nextProps;
    //如果批量更新的话，把updater实例添加到队列中
    if (updateQueue.isBatchingUpdate) {
      updateQueue.updaters.add(this);
    } else {
      this.updateComponent();
    }
  }
  //更新组件
  updateComponent() {
    let { classInstance, pendingStates, nextProps, callbacks } = this;
    if (nextProps || pendingStates.length > 0) {
      //需要更新
      shouldUpdate(classInstance, nextProps, this.getState());
    }
    if (callbacks.length) {
      callbacks.forEach((fn) => fn());
      callbacks.length = 0;
    }
  }

  //获取最新的状态
  getState() {
    let { classInstance, pendingStates } = this;
    //先获取老状态
    let { state } = classInstance;
    pendingStates.forEach((partialState) => {
      //setState 传入的是函数
      if (typeof partialState === "function") {
        partialState = partialState(state);
      }
      state = { ...state, ...partialState };
    });
    //清空缓存数组
    pendingStates.length = 0;
    return state;
  }
}

export class Component {
  static isReactComponent = true;
  constructor(props) {
    this.props = props;
    this.updater = new Updater(this);
  }

  setState(partialState, callback) {
    this.updater.addState(partialState, callback);
  }
  //让类组件强制更新
  forceUpdate() {
    //获取老的oldRenderVdom
    let oldRenderVdom = this.oldRenderVdom;
    //获取老的虚拟DOM 对应的真实DOM
    let oldDOM = findDOM(oldRenderVdom);
    //更新类组件的时候需要重新取值
    if (this.constructor.contextType) {
      this.context = this.constructor.contextType._currentValue;
    }
    if (this.constructor.getDerivedStateFromProps) {
      let newState = this.constructor.getDerivedStateFromProps(
        this.props,
        this.state
      );
      if (newState) {
        this.state = { ...this.state, ...newState };
      }
    }
    const snapshot =
      this.getSnapshotBeforeUpdate && this.getSnapshotBeforeUpdate();
    //获取新的虚拟dom
    let newRenderVdom = this.render();

    //虚拟树做对比 dom-diff 把得到的差异更新到真实DOM
    compareTwoVdom(oldDOM.parentNode, oldRenderVdom, newRenderVdom);

    this.oldRenderVdom = newRenderVdom;
    if (this.componentDidUpdate) {
      this.componentDidUpdate(this.props, this.state, snapshot);
    }
  }
}
